﻿using Microsoft.Data.SqlClient;
using MySql.Data.MySqlClient;
using System;
using System.Data.Common;

namespace Avin.Infrastructure.DbContext
{
    /// <summary>
    /// DbProviderFactory工厂类
    /// </summary>
    public class DataBaseProviderFactory
    {
        private static readonly string[] ProviderInvariantNames = new string[11];

        private static readonly DbProviderFactory[] ProviderFactoies = new DbProviderFactory[11];

        static DataBaseProviderFactory()
        {
            //加载已知的数据库访问类的程序集
            ProviderInvariantNames[(int)DbProviderType.SqlServer] = "System.Data.SqlClient";
            ProviderInvariantNames[(int)DbProviderType.OleDb] = "System.Data.OleDb";
            ProviderInvariantNames[(int)DbProviderType.ODBC] = "System.Data.ODBC";
            ProviderInvariantNames[(int)DbProviderType.Oracle] = "Oracle.DataAccess.Client";
            ProviderInvariantNames[(int)DbProviderType.MySql] = "MySql.Data.MySqlClient";
            ProviderInvariantNames[(int)DbProviderType.SQLite] = "System.Data.SQLite";
            ProviderInvariantNames[(int)DbProviderType.Firebird] = "FirebirdSql.Data.Firebird";
            ProviderInvariantNames[(int)DbProviderType.PostgreSql] = "Npgsql";
            ProviderInvariantNames[(int)DbProviderType.DB2] = "IBM.Data.DB2.iSeries";
            ProviderInvariantNames[(int)DbProviderType.Informix] = "IBM.Data.Informix";
            ProviderInvariantNames[(int)DbProviderType.SqlServerCe] = "System.Data.SqlServerCe";
        }

        /// <summary>
        /// 获取指定数据库类型对应的程序集名称
        /// </summary>
        /// <param name="providerType">数据库类型枚举</param>
        /// <returns></returns>
        public static string GetProviderInvariantName(DbProviderType providerType)
        {
            return ProviderInvariantNames[(int)providerType];
        }

        /// <summary>
        /// 获取指定类型的数据库对应的DbProviderFactory
        /// </summary>
        /// <param name="providerType">数据库类型枚举</param>
        /// <returns></returns>
        public static DbProviderFactory GetDbProviderFactory(DbProviderType providerType)
        {
            //如果还没有加载，则加载该DbProviderFactory
            if (ProviderFactoies[(int)providerType] == null)
            {
                ProviderFactoies[(int)providerType] = ImportDbProviderFactory(providerType);
            }
            return ProviderFactoies[(int)providerType];
        }

        /// <summary>
        /// 加载指定数据库类型的DbProviderFactory
        /// </summary>
        /// <param name="providerType">数据库类型枚举</param>
        /// <returns></returns>
        private static DbProviderFactory ImportDbProviderFactory(DbProviderType providerType)
        {
            //var providerName = ProviderInvariantNames[(int)providerType];
            DbProviderFactory factory = null;
            try
            {
                //从全局程序集中查找
                //factory = DbProviderFactories.GetFactory(providerName);


                switch (providerType)
                {
                    //.Net Core 写法
                    case DbProviderType.SqlServer:
                        factory = SqlClientFactory.Instance;
                        break;
                    case DbProviderType.MySql:
                        factory = MySqlClientFactory.Instance;
                        break;
                    case DbProviderType.SQLite:
                        break;
                    case DbProviderType.Oracle:
                        break;
                    case DbProviderType.ODBC:
                        break;
                    case DbProviderType.OleDb:
                        break;
                    case DbProviderType.Firebird:
                        break;
                    case DbProviderType.PostgreSql:
                        break;
                    case DbProviderType.DB2:
                        break;
                    case DbProviderType.Informix:
                        break;
                    case DbProviderType.SqlServerCe:
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(providerType), providerType, null);
                }
            }
            catch (ArgumentException)
            {
                factory = null;
            }
            return factory;
        }
    }
}
